/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ChatFrame.java
 *
 * Created on 2010/5/5, 下午 03:25:59
 */
package chat;

import chat.MsgEvent.*;
import chat.mybean.MyBean;
import compute.Compute;
import compute.Task;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditorSupport;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.EventObject;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JButton;

/**
 *
 * @author spider391Tang
 */
public class ChatFrame extends javax.swing.JFrame implements EventHandler, Compute {

    private PrintWriter out;
    ChatClient chat_client = null;
    Map<String, String> taskMap = new LinkedHashMap<String, String>();
    private String hostName;

    /** Creates new form ChatFrame */
    public ChatFrame() {
        initComponents();
        initBeans();
        chatTextPanel.addMouseListener(mouseTraceLabel1);
        chatTextPanel.addMouseMotionListener(mouseTraceLabel1);

        talkArea.setFocusable(false);

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        connectDlg = new javax.swing.JDialog();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        hostField = new javax.swing.JTextField();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        portField = new javax.swing.JTextField();
        mainPanel = new javax.swing.JPanel();
        beanPanel = new javax.swing.JPanel();
        plainPanel = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        talkArea = new chat.TalkArea();
        InputCommandLabel = new javax.swing.JLabel();
        cmdTextField = new javax.swing.JTextField();
        jScrollPane2 = new javax.swing.JScrollPane();
        chatTextPanel = new chat.wbPanel();
        mouseTraceLabel1 = new chat.MouseTraceLabel();
        jMenuBar1 = new javax.swing.JMenuBar();
        ConnectMenu = new javax.swing.JMenu();
        HelpMenu = new javax.swing.JMenu();

        connectDlg.setTitle("連線");

        jLabel1.setText("主機位址:");

        jLabel2.setText("連接阜:");

        hostField.setText("127.0.0.1");

        jButton1.setText("確定");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jButton2.setText("取消");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        portField.setText("7011");

        javax.swing.GroupLayout connectDlgLayout = new javax.swing.GroupLayout(connectDlg.getContentPane());
        connectDlg.getContentPane().setLayout(connectDlgLayout);
        connectDlgLayout.setHorizontalGroup(
            connectDlgLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(connectDlgLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(connectDlgLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1)
                    .addGroup(connectDlgLayout.createSequentialGroup()
                        .addComponent(hostField, javax.swing.GroupLayout.PREFERRED_SIZE, 157, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 44, Short.MAX_VALUE)
                        .addComponent(jButton1))
                    .addGroup(connectDlgLayout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(portField, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 117, Short.MAX_VALUE)
                        .addComponent(jButton2)))
                .addContainerGap())
        );
        connectDlgLayout.setVerticalGroup(
            connectDlgLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(connectDlgLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(connectDlgLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(hostField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButton1))
                .addGap(18, 18, 18)
                .addGroup(connectDlgLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(portField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButton2))
                .addContainerGap(16, Short.MAX_VALUE))
        );

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        beanPanel.setLayout(new java.awt.GridLayout(10, 1, 2, 2));

        plainPanel.setAutoscrolls(true);
        plainPanel.setCursor(new java.awt.Cursor(java.awt.Cursor.NW_RESIZE_CURSOR));
        plainPanel.setLayout(new java.awt.GridBagLayout());

        talkArea.setColumns(20);
        talkArea.setRows(5);
        jScrollPane1.setViewportView(talkArea);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(0, 0, 6, 0);
        plainPanel.add(jScrollPane1, gridBagConstraints);

        InputCommandLabel.setText("Input Command:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(4, 10, 2, 10);
        plainPanel.add(InputCommandLabel, gridBagConstraints);

        cmdTextField.setFocusCycleRoot(true);
        cmdTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cmdTextFieldActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        plainPanel.add(cmdTextField, gridBagConstraints);

        jScrollPane2.setPreferredSize(new java.awt.Dimension(500, 300));

        chatTextPanel.setBackground(new java.awt.Color(255, 255, 255));
        chatTextPanel.setPreferredSize(new java.awt.Dimension(450, 250));

        javax.swing.GroupLayout chatTextPanelLayout = new javax.swing.GroupLayout(chatTextPanel);
        chatTextPanel.setLayout(chatTextPanelLayout);
        chatTextPanelLayout.setHorizontalGroup(
            chatTextPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 498, Short.MAX_VALUE)
        );
        chatTextPanelLayout.setVerticalGroup(
            chatTextPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 298, Short.MAX_VALUE)
        );

        jScrollPane2.setViewportView(chatTextPanel);

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 500, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(beanPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 141, Short.MAX_VALUE))
            .addComponent(plainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(beanPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(plainPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        mouseTraceLabel1.setText("Show Pos");

        ConnectMenu.setText("連線");
        ConnectMenu.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                ConnectMenuMouseClicked(evt);
            }
        });
        jMenuBar1.add(ConnectMenu);

        HelpMenu.setText("說明");
        jMenuBar1.add(HelpMenu);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(10, 10, 10)
                        .addComponent(mouseTraceLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 142, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(mainPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(mainPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(mouseTraceLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    Socket chatSocket = null;

    private void cmdTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmdTextFieldActionPerformed

        javax.swing.JTextField source = (javax.swing.JTextField) evt.getSource();

        if (source.getText().startsWith("/leave")) {
            this.leave();
        } else if (source.getText().startsWith("/task")) {
            String[] names = ((String) source.getText()).split(" ");
            taskMap.put(names[1], source.getText().substring(names[0].length() + 1 + names[1].length() + 1));
            cmdTextField.setText("");
        } else if (source.getText().startsWith("/rexe")) {
            String[] names = ((String) source.getText()).split(" ");
            //System.out.println(names.length);
            /// 公子乖 -　/rexe
//            	Example: /rexe t1 user
//               In this command /rexe, the client sends the task t1 to the host of user for execution remotely.
//               If user is empty, the central server performs it.
            String task = getTaskType(names[1]);
            if (task == null) {
                return;
            }

            if (names.length > 2) {
                requestTask(task, names[2]);
            } else {
                requestTask(task, "@SERVER");
            }
            cmdTextField.setText("");
        } else if (source.getText().startsWith("/showtask")) {
            /// 公子乖 -　Task ID: t1, Task Type: Pi
            Set set = taskMap.entrySet();
            Iterator iterator = set.iterator();
            while (iterator.hasNext()) {
                Map.Entry me = (Map.Entry) iterator.next();
                String id = (String) me.getKey();
                String value = (String) me.getValue();
                String names[] = value.split(" ");
                this.talkArea.append("Task ID: " + id + ", Task Type: " + names[0] + "\n");
                cmdTextField.setText("");
            }

        } else {
            out.println(source.getText());
            cmdTextField.setText("");
        }
    }//GEN-LAST:event_cmdTextFieldActionPerformed

    private void ConnectMenuMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ConnectMenuMouseClicked
        connectDlg.setBounds((int) evt.getLocationOnScreen().getX() + 100, (int) (evt.getLocationOnScreen().getY() + 100), 280, 160);
        connectDlg.setVisible(true);
    }//GEN-LAST:event_ConnectMenuMouseClicked

    private Socket connect(String hostname, int port) {
        /// 公子乖 -　流程待改，若是輸入錯誤時應如何處理!!?
        try {
            chatSocket = new Socket(hostname, port);
            hostName = hostname;

        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: " + hostname);
            return null;
        } catch (IOException e) {
            System.out.println("**** The server does not exist.  Please type different domain and/or port.");
            return null;
        }
        return chatSocket;
    }

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        // TODO add your handling code here:
        connectDlg.setVisible(false);

        /// 公子乖 -　建立 socket 連線
        chatSocket = connect(hostField.getText(), Integer.parseInt(portField.getText()));
        try {
            out = new PrintWriter(chatSocket.getOutputStream(), true);
            chatTextPanel.setPrintOut(out);
        } catch (IOException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }

        chat_client = new ChatClient(chatSocket, out);
        try {
            chat_client.addHandler(talkArea, Class.forName("chat.MsgEvent.ShowEvent"));
            chat_client.addHandler(chatTextPanel, Class.forName("chat.MsgEvent.DrawBeanEvent"));
            chat_client.addHandler(chatTextPanel, Class.forName("chat.MsgEvent.MoveBeanEvent"));
            chat_client.addHandler(chatTextPanel, Class.forName("chat.MsgEvent.ChangeBeanEvent"));
            chat_client.addHandler(talkArea, Class.forName("chat.MsgEvent.MsgPostEvent"));
            chat_client.addHandler(talkArea, Class.forName("chat.MsgEvent.PostEvent"));
            chat_client.addHandler(this, Class.forName("chat.MsgEvent.KickUserEvent"));


        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        EventTransceiver chatLogin = new ChatLogin(chatSocket, talkArea, chatTextPanel, chat_client);
        try {
            chatLogin.addHandler(chatLogin, Class.forName("chat.MsgEvent.ShowEvent"));
            chatLogin.addHandler(chatLogin, Class.forName("chat.MsgEvent.LoginOKEvent"));
            chatLogin.addHandler(this, Class.forName("chat.MsgEvent.LoginOKEvent"));
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }



        //System.out.println("===>" + registry);
        //System.out.println("==> [Stub] " + stub);


        chatLogin.start();
        //chatLogin.leave();
        BeanManagerForTA.setWhiteBroad(chatTextPanel);
    }//GEN-LAST:event_jButton1ActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        // TODO add your handling code here:
        this.leave();
    }//GEN-LAST:event_formWindowClosing

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        // TODO add your handling code here:
        connectDlg.setVisible(false);

    }//GEN-LAST:event_jButton2ActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new ChatFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu ConnectMenu;
    private javax.swing.JMenu HelpMenu;
    private javax.swing.JLabel InputCommandLabel;
    private javax.swing.JPanel beanPanel;
    private chat.wbPanel chatTextPanel;
    private javax.swing.JTextField cmdTextField;
    private javax.swing.JDialog connectDlg;
    private javax.swing.JTextField hostField;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JPanel mainPanel;
    private chat.MouseTraceLabel mouseTraceLabel1;
    private javax.swing.JPanel plainPanel;
    private javax.swing.JTextField portField;
    private chat.TalkArea talkArea;
    // End of variables declaration//GEN-END:variables

    private void leave() {
        if (out != null) {
            out.println("/leave");
        }
        if (chat_client != null) {
            this.chat_client.leave();
        }
        System.exit(1);
    }

    public void handleEvent(EventObject e) {
        if (e instanceof KickUserEvent) {

            this.leave();
        } else if (e instanceof LoginOKEvent) {
            String author = (String) e.getSource();
            this.chatTextPanel.setAuthor(author);
            this.setTitle(author);
            System.out.println(author);
            reg_to_rmi(author);
        }
    }

    public <T> T executeTask(Task<T> t, String target) throws RemoteException {
        System.out.println(t + ": " + target);
        t.init(target);
        return t.execute();
    }

    private void reg_to_rmi(String name) {
        /// 公子乖 -　向 rmiregistry 註冊，使用預設 port 1099
        // 	Each client uses his name for rebind().
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        Compute engine = new ChatFrame();
        Compute stub;
        try {
            stub = (Compute) UnicastRemoteObject.exportObject(engine, 0);
            Registry registry = LocateRegistry.getRegistry();
            registry.rebind(name, stub);
            System.out.println(name + " bound to RMIRegisty");
        } catch (RemoteException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private String getTaskType(String task_id) {
        Set set = taskMap.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Map.Entry me = (Map.Entry) iterator.next();
            String id = (String) me.getKey();
            if (task_id.equals(id)) {
                return (String) me.getValue();
            }
        }
        return null;
    }

    private void requestTask(String task, String user) {
        String[] names = task.split(" ");

        Class taskClass;
        Task task_obj = null;
        try {
            taskClass = Class.forName("compute." + names[0]);
            System.out.println(taskClass);
            task_obj = (Task) taskClass.newInstance();
            System.out.println(task_obj);
        } catch (InstantiationException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }

        Registry registry;
        Compute comp = null;
        try {
            registry = LocateRegistry.getRegistry(hostName);
            comp = (Compute) registry.lookup(user);
        } catch (NotBoundException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (AccessException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (RemoteException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }

        //task_obj.init(task.substring(names[0].length() + 1));
        Object ret_obj = null;
        try {
            ret_obj = comp.executeTask(task_obj, task.substring(names[0].length() + 1));
        } catch (RemoteException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println(ret_obj);

        //System.out.println(registry);
        //System.out.println(comp);
        //Pi task = new Pi(Integer.parseInt("45"));
        //System.out.println(task);
        //BigDecimal pi = comp.executeTask(task);


    }
    // End of variables declaration

    public class AL implements ActionListener {

        String beanName = null;

        public AL(String beanName) {
            this.beanName = beanName;
        }

        public void actionPerformed(ActionEvent e) {
            //System.out.println(e);
            chatTextPanel.setBeanName(beanName);
            chatTextPanel.setStatus(wbPanel.DragStatus.Draw);
        }
    }

    protected static ImageIcon createImageIcon(String path,
            String description) {
        java.net.URL imgURL = ChatFrame.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    /// 公子乖 -　以下兩個函式從網路上找來，用來列舉 Package 內的 classes
    /**
     * Scans all classes accessible from the context class loader which belong to the given package and subpackages.
     *
     * @param packageName The base package
     * @return The classes
     * @throws ClassNotFoundException
     * @throws IOException
     */
    private static Class[] getClasses(String packageName)
            throws ClassNotFoundException, IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        assert classLoader != null;
        String path = packageName.replace('.', '/');
        Enumeration<URL> resources = classLoader.getResources(path);
        List<File> dirs = new ArrayList<File>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        ArrayList<Class> classes = new ArrayList<Class>();
        for (File directory : dirs) {
            classes.addAll(findClasses(directory, packageName));
        }
        return classes.toArray(new Class[classes.size()]);
    }

    /**
     * Recursive method used to find all classes in a given directory and subdirs.
     *
     * @param directory   The base directory
     * @param packageName The package name for classes found inside the base directory
     * @return The classes
     * @throws ClassNotFoundException
     */
    private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {
        List<Class> classes = new ArrayList<Class>();
        if (!directory.exists()) {
            return classes;
        }
        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                assert !file.getName().contains(".");
                classes.addAll(findClasses(file, packageName + "." + file.getName()));
            } else if (file.getName().endsWith(".class")) {
                classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
            }
        }
        return classes;
    }

    BeanInfo getBeanInfo(Object bean_obj) {
        BeanInfo info = null;
        try {
            info = Introspector.getBeanInfo(bean_obj.getClass());
        } catch (java.beans.IntrospectionException ex) {
            ex.printStackTrace();
        }
        for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
            String field_name = pd.getName(); // get property (or field) name
            Method get_method = pd.getReadMethod();  // get getField()
            Method set_method = pd.getWriteMethod(); // get setField()
            pd.getValue(field_name);
            if (field_name.startsWith("wb")) {

                System.out.println("==> " + field_name);
                pd.getValue(field_name);
                System.out.println(get_method);
                System.out.println(set_method);

                PropertyEditorSupport i;
            }
            // Ignore those without starting with “wb”.
            // For all fields, “wbField”, extract “Field”.
        }
        return info;
    }

    private void initBeans() {
        try {
            //throw new UnsupportedOperationException("Not yet implemented");
            //System.out.println(getClasses("chata"));
            Class[] classes = getClasses("chat");
            System.out.println(classes.length);
            for (int i = 0; i < classes.length; i++) {
                /// 公子乖 -　很髒的做法，看不下去!! 待改~
                if (classes[i].toString().endsWith("Bean") && !classes[i].toString().endsWith("MyBean")) {
                    System.out.println(classes[i].getName());
                    /// 公子乖 -　看例子 chat.CircleBean
                    String[] names = classes[i].getName().split("\\.");

                    String beanName = names[names.length - 1];
                    beanName = beanName.substring(0, beanName.length() - 4);

                    JButton btn = new JButton();
                    beanPanel.add(btn);
                    btn.setText(beanName);
                    btn.addActionListener(new AL(classes[i].getName()));


                }
            }

        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(ChatFrame.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}
